﻿using Microsoft.EntityFrameworkCore.Metadata.Internal;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using DocumentFormat.OpenXml.Packaging;
using Office.Automatic.Library.Data;
using Office.Automatic.Library.Data.Utils.Excel;
using Word=DocumentFormat.OpenXml.Wordprocessing;
using Drawing = DocumentFormat.OpenXml.Drawing;
using WP= DocumentFormat.OpenXml.Drawing.Wordprocessing;

namespace Office.Automatic.Core.Jobs
{
    internal class Job制作花名册:Job
    {
#pragma warning disable CS8618 // 在退出构造函数时，不可为 null 的字段必须包含非 null 值。请考虑声明为可以为 null。
        [Sheet("Sheet0", HasHeadRow = true)]
        class DataItem
        {
            public int 序号 { get; set; }
            public string 姓名 { get; set; }
            public string KEY { get; set; }
            public string 相片别称 { get; set; }
            public string 单位 { get; set; }
            public string 部门 { get; set; }
            public DateTime 出生日期 { get; set; }
            public string 籍贯 { get; set; }
            public string 政治面貌 { get; set; }
            public string 职务职级描述 { get; set; }
            public string 备注 { get; set; }
            public string 电话号码 { get; set; }
            public string 手机号码 { get; set; }
            public string 职称 { get; set; }

        }
#pragma warning restore CS8618 // 在退出构造函数时，不可为 null 的字段必须包含非 null 值。请考虑声明为可以为 null。

        class Photo
        {
            public string Name { get; set; }
            public string Path { get; set; }

            public long Size { get; set; }

            public Photo(string name, string path, long size)
            {
                Name = name;
                Path = path;
                Size = size;
            }
        }

        public override string Name => "制作花名册";

        public override bool IsTemporary => false;

        private Dictionary<string, Photo> _nameToPhotosDict = new();
        public override void Process()
        {
            var data = Importer.ImportFromExcel<DataItem>(@"C:\Users\loyse\Desktop\Workspace\20221118-人员花名册\20240116103620.xlsx",
                new ImportSetting()
                {
                    LimitToHeadRange = true
                });

            LoadPhotos();

            CreateBook(data);
        }


        private void CreateBook(DataItem[] data)
        {
            // Copy template
            var targetPath = GetOutputDocumentPath();
            File.Copy(AcquireTemplateTablePath(), targetPath);

            using var document = WordprocessingDocument.Open(targetPath, true);
            var documentBody = document.MainDocumentPart?.Document?.Body;

            if(documentBody == null)
                return;
            
            var sampleTable = documentBody.GetFirstChild<Word.Table>();

            if (sampleTable == null) return;

            var tableCount = Convert.ToInt32(Math.Ceiling((data.Length + 0.0d) / 4.0d));

            for (var i = 1; i < tableCount; i++)
            {
                var newTable = sampleTable.CloneNode(true);
                documentBody.InsertAfter(newTable, sampleTable);
            }

            var tables = documentBody.Elements<Word.Table>();

            tableCount = 0;
            foreach (var table in tables)
            {
                for (var j = 0; j < 4; j++)
                {
                    var index = tableCount * 4 + j;
                    if (index >= data.Length) break;
                    Console.Write("Handle data item {0}...", data[index].姓名);
                    WriteTable(j, data[index], table, document);
                    Console.WriteLine("Ok");
                }

                tableCount++;
            }

            document.Save();
        }

        private void WriteTableCellValue(Word.Table table, int rowIndex, int colIndex, string value)
        {
            table.Elements<Word.TableRow>().ElementAt(rowIndex).Elements<Word.TableCell>().ElementAt(colIndex)
                .GetFirstChild<Word.Paragraph>().GetFirstChild<Word.Run>().GetFirstChild<Word.Text>().Text = value;
        }

        private void WriteTableDepartment(Word.Table table, int rowIndex, int colIndex, string value)
        {
            table.Elements<Word.TableRow>().ElementAt(rowIndex).Elements<Word.TableCell>().ElementAt(colIndex)
                .GetFirstChild<Word.Paragraph>().Elements<Word.Run>().ElementAt(1).GetFirstChild<Word.Text>().Text = value;
        }

        private void WriteTableLongValue(Word.Table table, int rowIndex, int colIndex, string value)
        {
            var paragraph = table.Elements<Word.TableRow>().ElementAt(rowIndex).Elements<Word.TableCell>().ElementAt(colIndex)
                .GetFirstChild<Word.Paragraph>();
            if (paragraph == null) return;

            var size = value.Length > 19 ? 24 : 28;

            var pPr= paragraph.GetFirstChild<Word.ParagraphProperties>();
            pPr.GetFirstChild<Word.ParagraphMarkRunProperties>()
                .GetFirstChild<Word.FontSize>().Val = "24";
            pPr.GetFirstChild<Word.ParagraphMarkRunProperties>()
                .GetFirstChild<Word.FontSizeComplexScript>().Val = "24";


            var run = new Word.Run()
            {
                InnerXml =
                    $"<w:rPr>\r\n          <w:rFonts w:hint=\"eastAsia\" w:ascii=\"思源黑体 CN Normal\" w:hAnsi=\"思源黑体 CN Normal\"\r\n            w:eastAsia=\"思源黑体 CN Normal\" />\r\n          <w:sz w:val=\"{size}\" />\r\n          <w:szCs w:val=\"{size}\" />\r\n        </w:rPr>\r\n        <w:t>{value}</w:t>"
            };

            paragraph.RemoveAllChildren<Word.Run>();
            paragraph.AppendChild(run);
        }

        private static int photoIndex = 0;

        private void InsertPhoto(WordprocessingDocument document, Word.Table table, int index, string photoKey)
        {
            Photo photo;
            if (!_nameToPhotosDict.TryGetValue(photoKey, out photo))
            {
                return;
            }

            var imagePart = document.MainDocumentPart.AddImagePart(ImagePartType.Jpeg);
            using (var imageStream = File.OpenRead(photo.Path))
            {
                imagePart.FeedData(imageStream);
            }

            var partId = document.MainDocumentPart.GetIdOfPart(imagePart);
            photoIndex++;

            var cell = table.Elements<Word.TableRow>().ElementAt(index * 6 + 1).Elements<Word.TableCell>().ElementAt(0);
            cell.RemoveAllChildren();
            var sb = new StringBuilder();
            sb.Append(DrawingTemplate);
            sb.Replace("{PHOTO-INDEX}", photoIndex.ToString());
            sb.Replace("{PHOTO-NAME}", photoKey);
            sb.Replace("{PART-ID}", partId.ToString());

            cell.InnerXml = PhotoTemplate;

            var drawing = cell.GetFirstChild<Word.Paragraph>()?.GetFirstChild<Word.Run>()
                ?.GetFirstChild<Word.Drawing>();
            if (drawing == null)
            {
                return;
            }


            var inline = new WP.Inline();
            inline.DistanceFromBottom = 0;
            inline.DistanceFromLeft = 0;
            inline.DistanceFromRight = 0;
            inline.DistanceFromTop = 0;

            inline.InnerXml = sb.ToString();

            var blip=inline.GetFirstChild<Drawing.Graphic>()?.GraphicData.GetFirstChild<Drawing.Pictures.Picture>()
                ?.GetFirstChild<Drawing.Pictures.BlipFill>()?.GetFirstChild<Drawing.Blip>();

            if(blip == null) { return; }

            blip.Embed = partId;

            drawing.AppendChild(inline);
        }

        private void WriteTable(int index, DataItem data, Word.Table table, WordprocessingDocument document)
        {
            var offset = 6 * index;

            WriteTableDepartment(table, offset, 0, data.单位);
            WriteTableCellValue(table, offset, 1, string.IsNullOrEmpty(data.部门) ? string.Empty : data.部门);
            WriteTableCellValue(table, offset + 1, 2, data.姓名);
            WriteTableCellValue(table, offset + 1, 4, data.出生日期.ToString("yyyy.MM"));
            WriteTableCellValue(table, offset + 2, 2, data.籍贯);
            WriteTableCellValue(table, offset + 2, 4, data.政治面貌);
            WriteTableLongValue(table, offset + 3, 2, data.职务职级描述);
            WriteTableLongValue(table, offset + 4, 2, data.职称 ?? "");
            WriteTableCellValue(table, offset + 5, 2, string.IsNullOrEmpty(data.电话号码) ? string.Empty : data.电话号码);
            WriteTableCellValue(table, offset + 5, 4, data.手机号码);
            InsertPhoto(document, table, index, string.IsNullOrEmpty(data.相片别称) ? data.KEY : data.相片别称);
        }

        private void LoadPhotos()
        {
            var path = AcquirePhotoRootFolderPath();

            var photos = Directory.GetFiles(path, "*.jpg", SearchOption.AllDirectories);
            var regex = new Regex("[\\u4e00-\\u9fa5]{2,3}");
            foreach (var photo in photos)
            {
                var match = regex.Match(Path.GetFileNameWithoutExtension(photo));
                if (match.Success)
                {
                    var name = match.Value;
                    var fileInfo = new FileInfo(photo);
                    if (_nameToPhotosDict.ContainsKey(name))
                    {
                        var p = _nameToPhotosDict[name];
                        if (p.Size < fileInfo.Length)
                        {
                            p.Size=fileInfo.Length;
                            p.Path = photo;
                        }
                    }
                    else
                    {
                        _nameToPhotosDict.Add(name, new Photo(name, photo, fileInfo.Length));
                    }
                }
            }
        }
        
        private string AcquirePhotoRootFolderPath()
        {
            return "C:\\Users\\loyse\\Desktop\\Workspace\\20221118-人员花名册\\2018年工作照片";
        }

        private string AcquireTemplateTablePath()
        {
            return @"C:\Users\loyse\Desktop\Workspace\20221118-人员花名册\TEMPLATE-V2.docx";
        }

        private string GetOutputDocumentPath()
        {
            return $"C:\\Users\\loyse\\Desktop\\Workspace\\20221118-人员花名册\\Output-{DateTime.Now:HH-mm-ss}.docx";
        }

        private const string PhotoTemplate = @"<w:tcPr>
  <w:tcW w:w=""2689"" w:type=""dxa"" />
  <w:vMerge w:val=""restart"" />
  <w:tcBorders>
    <w:top w:val=""single"" w:sz=""4"" w:space=""0"" w:color=""auto"" />
    <w:left w:val=""single"" w:sz=""8"" w:space=""0"" w:color=""auto"" />
  </w:tcBorders>
  <w:tcMar>
    <w:left w:w=""113"" w:type=""dxa"" />
    <w:right w:w=""113"" w:type=""dxa"" />
  </w:tcMar>
</w:tcPr>
<w:p w:rsidR=""005413F2""
  w:rsidRDefault=""005413F2"" w:rsidP=""005413F2"">
  <w:pPr>
    <w:jc w:val=""center"" />
  </w:pPr>
  <w:r w:rsidRPr=""005413F2"">
    <w:rPr>
      <w:noProof />
    </w:rPr>
    <w:drawing>
    </w:drawing>
  </w:r>
</w:p>";

        private const string DrawingTemplate = @"
        <wp:extent cx=""1463675"" cy=""1992312"" />
        <wp:effectExtent l=""0"" t=""0"" r=""3175"" b=""8255"" />
        <wp:docPr id=""{PHOTO-INDEX}"" name=""图片 {PHOTO-INDEX}"" descr=""{PHOTO-NAME}"" />
        <wp:cNvGraphicFramePr>
          <a:graphicFrameLocks
            xmlns:a=""http://schemas.openxmlformats.org/drawingml/2006/main""
            noChangeAspect=""1"" />
        </wp:cNvGraphicFramePr>
        <a:graphic xmlns:a=""http://schemas.openxmlformats.org/drawingml/2006/main"">
          <a:graphicData uri=""http://schemas.openxmlformats.org/drawingml/2006/picture"">
            <pic:pic xmlns:pic=""http://schemas.openxmlformats.org/drawingml/2006/picture"">
              <pic:nvPicPr>
                <pic:cNvPr id=""{PHOTO-INDEX}"" name=""图片 {PHOTO-INDEX}"" descr=""{PHOTO-NAME}"" />
                <pic:cNvPicPr>
                  <a:picLocks noChangeAspect=""1"" />
                </pic:cNvPicPr>
              </pic:nvPicPr>
              <pic:blipFill>
                <a:blip />
                <a:stretch>
                  <a:fillRect />
                </a:stretch>
              </pic:blipFill>
              <pic:spPr>
                <a:xfrm>
                  <a:off x=""0"" y=""0"" />
                  <a:ext cx=""1463675"" cy=""1992312"" />
                </a:xfrm>
                <a:prstGeom prst=""rect"">
                  <a:avLst />
                </a:prstGeom>
                <a:noFill />
                <a:ln w=""9525"">
                  <a:noFill />
                </a:ln>
              </pic:spPr>
            </pic:pic>
          </a:graphicData>
        </a:graphic>";
    }
}
